package com.sikulifang.frequency.core;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.sikulifang.frequency.domain.FrequencyProperties;
import com.sikulifang.frequency.service.IFrequency;
import com.sikulifang.frequency.service.impl.MultiTypeFrequency;
import com.sikulifang.frequency.service.impl.SingleTypeFrequency;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 频率控制上下文
 *
 * @author zhoul 2020-11-18
 * @since 3.0.0
 */
public class FrequencyContext {

    /**
     * 存放银行限制类
     */
    private static final ConcurrentMap<String, IFrequency> FREQUENCY_MAP = new ConcurrentHashMap<>();

    /**
     * 存储当前线程的交易类型
     */
    private static final ThreadLocal<String> TYPE = new TransmittableThreadLocal<>();

    /**
     * 存储获取锁的第一时间
     */
    private static final ThreadLocal<Long> START_TIME = new TransmittableThreadLocal<>();

    private FrequencyContext() {
    }

    /**
     * 创建银行限流实例
     *
     * @param bank                银行
     * @param frequencyProperties 参数类型
     */
    public static void createInstance(String bank, FrequencyProperties frequencyProperties) {
        //移除该银行久的类型
        for (String key : FREQUENCY_MAP.keySet()) {
            if (key.startsWith(bank)) {
                FREQUENCY_MAP.remove(key);
            }
        }

        int mode = frequencyProperties.getMode();
        if (IFrequency.ONLY_QUERY == mode || IFrequency.QUERY_TRADE_SEPARATE == mode) {
            SingleTypeFrequency query = new SingleTypeFrequency();
            query.setInterfaceInterval(frequencyProperties.isQueryInterval());
            query.setInterfaceDelayTime(frequencyProperties.getQueryDelayTime());
            query.setInterfaceWaitingTime(frequencyProperties.getQueryWaitingTime());
            query.setInterval(frequencyProperties.isInterval());
            query.setIntervalTime(frequencyProperties.getIntervalTime());
            FREQUENCY_MAP.put(bank + ":" + "query", query);
        }
        if (IFrequency.ONLY_TRADE == mode || IFrequency.QUERY_TRADE_SEPARATE == mode) {
            SingleTypeFrequency trade = new SingleTypeFrequency();
            trade.setInterfaceInterval(frequencyProperties.isTradeInterval());
            trade.setInterfaceDelayTime(frequencyProperties.getTradeDelayTime());
            trade.setInterfaceWaitingTime(frequencyProperties.getTradeWaitingTime());
            trade.setInterval(frequencyProperties.isInterval());
            trade.setIntervalTime(frequencyProperties.getIntervalTime());
            FREQUENCY_MAP.put(bank + ":" + "trade", trade);
        }

        if (IFrequency.QUERY_TRADE == mode) {
            MultiTypeFrequency multiTypeFrequency = new MultiTypeFrequency();

            multiTypeFrequency.setQueryInterval(frequencyProperties.isQueryInterval());
            multiTypeFrequency.setQueryDelayTime(frequencyProperties.getQueryDelayTime());
            multiTypeFrequency.setQueryWaitingTime(frequencyProperties.getQueryWaitingTime());

            multiTypeFrequency.setTradeInterval(frequencyProperties.isTradeInterval());
            multiTypeFrequency.setTradeDelayTime(frequencyProperties.getTradeDelayTime());
            multiTypeFrequency.setTradeWaitingTime(frequencyProperties.getTradeWaitingTime());

            multiTypeFrequency.setInterval(frequencyProperties.isInterval());
            multiTypeFrequency.setIntervalTime(frequencyProperties.getIntervalTime());

            FREQUENCY_MAP.put(bank + ":" + "query:multi", multiTypeFrequency);
            FREQUENCY_MAP.put(bank + ":" + "trade:multi", multiTypeFrequency);
        }
    }

    /**
     * 设置接口类型
     *
     * @param bank 银行
     * @param type 类型，trade 交易，query 查询
     */
    public static void setType(String bank, String type) {
        TYPE.set(bank + ":" + type);
    }

    private static String getSimpleType() {
        String type = TYPE.get();
        return type.substring(type.indexOf(":") + 1);
    }

    private static synchronized IFrequency getFrequency() {
        IFrequency efficiency = FREQUENCY_MAP.get(TYPE.get() + ":multi");
        if (efficiency == null) {
            return FREQUENCY_MAP.get(TYPE.get());
        }
        return efficiency;
    }

    /**
     * 获取锁
     */
    public static void acquire() throws InterruptedException {
        IFrequency frequency = getFrequency();
        if (frequency != null) {
            frequency.acquire(getSimpleType());
            START_TIME.set(System.currentTimeMillis());
        }
    }

    /**
     * 延迟时间
     */
    public static void delay() {
        IFrequency frequency = getFrequency();
        if (frequency != null) {
            if (null != START_TIME.get()) {
                long time = System.currentTimeMillis() - START_TIME.get();
                frequency.delay(getSimpleType(), time);
            }
        }
    }

    /**
     * Description: 释放锁, release 会添加 信号量
     * <p>
     * Date: 2023年7月18日, 0018 14:58
     *
     * @param automaticDelay 是否自动进行延时处理
     */
    public static void release(boolean automaticDelay) {
        if (automaticDelay) {
            delay();
        }
        release();
    }

    /**
     * 释放锁
     */
    public static void release() {
        IFrequency efficiency = getFrequency();
        if (efficiency != null) {
            efficiency.release(getSimpleType());
        }
        START_TIME.remove();
        TYPE.remove();
    }

}
